/*
 * log.c
 *
 * Copyright (C) 2011 - Dr.NP
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * @version log.c 1.0.0
 * @package libbspcore
 * @author Dr.NP <mp@bsgroup.org>
 * @update 04/01/2011
 */

/**
 * Event log operator
 *
 * === CHANGELOG ===
 * [04/01/2011] - Creation
 */

#include "bsp.h"

#include "bsp_conf.h"
#include "bsp_log.h"
#include "bsp_utils.h"

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <pthread.h>

static char is_open = 0;
static time_t log_time = 0;
static char log_filename[LOG_FILENAME_LENGTH];
int log_fd;
pthread_mutex_t log_write_log = PTHREAD_MUTEX_INITIALIZER;

const char *log_type(int);

int log_init()
{
    conf_set("LOG_BASEDIR", "./log", CONF_LEVEL_INIT);
    conf_set("LOG_FREQUENCY", "none", CONF_LEVEL_INIT);
    is_open = 0x0;
    
    return RTN_SUCCESS;
}

void log_add(int level, const char *fmt, ...)
{
    time_t now = time((time_t *) NULL);
    int t = 0, len;
    char *log_frequency = conf_get("LOG_FREQUENCY"), need_reopen = 0;
    struct tm *loctime;
    static char tgdate[DATE_SIZE], scdate[DATE_SIZE];
    static char line[LOG_LINE_LENGTH], data[LOG_LINE_LENGTH];
    va_list ap;

    if (!log_frequency)
    {
        log_frequency = "none";
    }

    if (0 == strncmp(log_frequency, "hourly", 6))
    {
        loctime = localtime(&now);
        strftime(tgdate, DATE_SIZE, "%Y%m%d%H", loctime);
        loctime = localtime(&log_time);
        strftime(scdate, DATE_SIZE, "%Y%m%d%H", loctime);
    }

    else if (0 == strncmp(log_frequency, "daily", 5))
    {
        loctime = localtime(&now);
        strftime(tgdate, DATE_SIZE, "%Y%m%d", loctime);
        loctime = localtime(&log_time);
        strftime(scdate, DATE_SIZE, "%Y%m%d", loctime);
    }

    else if (0 == strncmp(log_frequency, "weekly", 6))
    {
        loctime = localtime(&now);
        strftime(tgdate, DATE_SIZE, "%Y%W", loctime);
        loctime = localtime(&log_time);
        strftime(scdate, DATE_SIZE, "%Y%W", loctime);
    }

    else if (0 == strncmp(log_frequency, "monthly", 7))
    {
        loctime = localtime(&now);
        strftime(tgdate, DATE_SIZE, "%Y%m", loctime);
        loctime = localtime(&log_time);
        strftime(scdate, DATE_SIZE, "%Y%m", loctime);
    }

    else if (0 == strncmp(log_frequency, "yearly", 6))
    {
        loctime = localtime(&now);
        strftime(tgdate, DATE_SIZE, "%Y", loctime);
        loctime = localtime(&log_time);
        strftime(scdate, DATE_SIZE, "%Y", loctime);
    }

    else
    {
        // Single log file
        tgdate[0] = 0;
        scdate[0] = 0;
        snprintf(log_filename, LOG_FILENAME_LENGTH - 1, "%s/bsp.log", conf_get("LOG_BASEDIR"));
    }

    if (0 != strcmp(tgdate, scdate))
    {
        // I need a new log file
        snprintf(log_filename, LOG_FILENAME_LENGTH - 1, "%s/bsp_%s.log", conf_get("LOG_BASEDIR"), tgdate);
        need_reopen = 1;
    }

    pthread_mutex_lock(&log_write_log);
    if (need_reopen && is_open)
    {
        close(log_fd);
        is_open = 0;
    }

    if (!is_open)
    {
        log_fd = open(log_filename, O_CREAT | O_WRONLY | O_APPEND, 0644);
        if (log_fd < 0)
        {
            fprintf(stderr, "Log file %s open failed\n", log_filename);
            return;
        }

        set_nonblock(log_fd);
        is_open = 1;
        set_fd(log_fd, 0, FD_TYPE_NORMAL);
    }

    va_start(ap, fmt);
    vsnprintf(data, LOG_LINE_LENGTH - 2, fmt, ap);
    va_end(ap);

    loctime = localtime(&now);
    strftime(tgdate, DATE_SIZE, "%m/%d/%Y %H:%M:%S", loctime);
    
    snprintf(line, LOG_LINE_LENGTH - 1, "[%s] - [%s] : %s\n", tgdate, log_type(level), data);
    len = strlen(line);
    while (t < len)
    {
        t += write(log_fd, line, len);
    }
    
    pthread_mutex_unlock(&log_write_log);
    
    return;
}

const char * log_type(int level)
{
    const char *list[] = 
    {
        "EVENT", 
        "NOTICE", 
        "ERROR"
    };
    int t = sizeof(list) / sizeof(char *);

    if (level < 0 || level >= t)
    {
        return "UNKNOWN";
    }

    return list[level];
}
